/*----------------------------------------------------------------------------
 * Copyright (c) <2018>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/
/**
 *  DATE                AUTHOR      INSTRUCTION
 *  2020-02-05 17:00  zhangqianfu  The first version
 *
 */
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "ohos_init.h"
#include "ohos_types.h"
#include "ohos_errno.h"
#include "cmsis_os2.h"

#include "iot_gpio.h"
#include "iot_pwm.h"
#include "iot_adc.h"

#include "motor.h"
#include "oc_mqtt.h"
#include "wifi_connect.h"
#include "lwip/sockets.h"

#define MSGQUEUE_OBJECTS 16 // 消息队列对象的数量

extern int Window_flag = 0;//窗口标记位 1--开窗 0--关窗
extern int Rain_flag = 0;//雨滴标记位  1--下雨 0--无雨

typedef struct
{ // object data type
    char *Buf;
    uint8_t Idx;
} MSGQUEUE_OBJ_t;

MSGQUEUE_OBJ_t msg;
osMessageQueueId_t mid_MsgQueue; // 消息队列ID

//华为云密钥信息
#define CLIENT_ID "62062355de9933029be769ff_201906100052_0_0_2022021109"
#define USERNAME "62062355de9933029be769ff_201906100052"
#define PASSWORD "2d524c6fdd13a6c2392e61e16bac910532ed99bfd1117e72c5cc3dcad72d7b87"

typedef enum
{
    en_msg_cmd = 0,
    en_msg_report,
} en_msg_type_t;

typedef struct
{
    char *request_id;
    char *payload;
} cmd_t;

typedef struct
{
    int voltage;
    int Window_flag;
    int Rain_flag;
} report_t;

typedef struct
{
    en_msg_type_t msg_type;
    union
    {
        cmd_t cmd;
        report_t report;
    } msg;
} app_msg_t;

typedef struct
{
    //int connected;
    int motor;
    int Window_flag;
    int Rain_flag;
} app_cb_t;
static app_cb_t g_app_cb;

//属性名称与华为云平台一一对应
static void deal_report_msg(report_t *report)
{
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t voltage;
    oc_mqtt_profile_kv_t Window_flag;
    oc_mqtt_profile_kv_t Rain_flag;
    oc_mqtt_profile_kv_t motor;

    service.event_time = NULL;
    service.service_id = "Balcony";
    service.service_property = &voltage;
    service.nxt = NULL;

    voltage.key = "voltage";
    voltage.value = &report->voltage;
    voltage.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    voltage.nxt = &Window_flag;

    Window_flag.key = "Window_flag";
    Window_flag.value = g_app_cb.Window_flag ? "ON" : "OFF";
    Window_flag.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    Window_flag.nxt = &Rain_flag;

    Rain_flag.key = "Rain_flag";
    Rain_flag.value = g_app_cb.Rain_flag ? "ON" : "OFF";
    Rain_flag.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    Rain_flag.nxt = &motor;

    motor.key = "Motor_Status";
    motor.value = g_app_cb.motor ? "ON" : "OFF";
    motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    motor.nxt = NULL;

    oc_mqtt_profile_propertyreport(USERNAME, &service);
    return;
}

void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    app_msg_t *app_msg;

    int ret = 0;
    app_msg = malloc(sizeof(app_msg_t));
    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.payload = (char *)recv_data;

    printf("recv data is %.*s\n", recv_size, recv_data);
    ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U);
    if (ret != 0)
    {
        free(recv_data);
    }
    *resp_data = NULL;
    *resp_size = 0;
}

//华为IoT平台下发命令控制
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;

    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root)
    {
        goto EXIT_JSONPARSE;
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname)
    {
        goto EXIT_CMDOBJ;
    }
    //命令控制---马达
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Balcony_Control_Motor"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        //操作电动马达
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.motor = 1;
            MotorStatusSet(ON);//开窗
            g_app_cb.Window_flag = 1;
            Window_flag = 1;
        }
        else
        {
            g_app_cb.motor = 0;
            MotorStatusSet(OFF);//关窗
            g_app_cb.Window_flag = 0;
            Window_flag = 0;
        }
        cmdret = 0;
    }

EXIT_OBJPARA:
EXIT_OBJPARAS:
EXIT_CMDOBJ:
    cJSON_Delete(obj_root);
EXIT_JSONPARSE:
    ///< do the response
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
    return;
}

static int task_main_entry(void)
{
    app_msg_t *app_msg;

    uint32_t ret = WifiConnect("Mai", "00000000");//wifi账号密码

    device_info_init(CLIENT_ID, USERNAME, PASSWORD);
    oc_mqtt_init();
    oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);

    while (1)
    {
        app_msg = NULL;
        (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U);
        if (NULL != app_msg)
        {
            switch (app_msg->msg_type)
            {
            case en_msg_cmd:
                deal_cmd_msg(&app_msg->msg.cmd);
                break;
            case en_msg_report:
                deal_report_msg(&app_msg->msg.report);
                break;
            default:
                break;
            }
            free(app_msg);
        }
    }
    return 0;
}

static int task_sensor_entry(void)
{
    app_msg_t *app_msg;
    
    float voltage;
    unsigned short val;
    

    Motor_Init();//电动马达初始化
    YUDI_Init();//雨滴传感器初始化

    printf("\n\n");
    printf("雨滴传感器三秒读取一次数据\n");

    while (1)
    {
        app_msg = malloc(sizeof(app_msg_t));
        //获取ADC1采集值---雨滴传感器
        unsigned int ret;
        ret = IoTAdcRead(IOT_ADC_CHANNEL_1, &val, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 256);
        if (ret != EC_SUCCESS)
        {
            printf("ADC Read Fail\n");
            continue;
        }

        //将ADC1采集值转换成电压值
        voltage = IOTAdcConvertToVoltage(val)*10;//将电压数值x10，以便数据分析与观察
        if(voltage >= 33.850){Rain_flag=0;g_app_cb.Rain_flag=0;}//雨滴板电压大于3.385--下雨标记位--0--无雨
        if(voltage < 33.850){Rain_flag=1;g_app_cb.Rain_flag=1;}//雨滴板电压小于3.385--下雨标记位--1--下雨

        //无雨标记--无雨并且关着窗
        if(Rain_flag == 0 && Window_flag == 0){
            printf("无雨、窗户关着!\r\n");
            Rain_flag=0;Window_flag=0;
            
        }
        if(Rain_flag == 0 && Window_flag == 1){
            printf("无雨、窗户开着!\r\n");
            Rain_flag=0;Window_flag=1;
            
        }
        if(Rain_flag == 1 && Window_flag == 0){
            printf("下雨、窗户关着!\r\n");
            Rain_flag=1;Window_flag=0;
            
        }
        //下雨标记--下雨并且开着窗(关窗)
        if(Rain_flag == 1 && Window_flag == 1){
            printf("下雨、窗户开着、即将关窗!\r\n");
            g_app_cb.motor = 0;
            MotorStatusSet(OFF);//关窗
            g_app_cb.Window_flag=0;
            Rain_flag=1;Window_flag=0;
            
        }

        //打印雨滴传感器电压值、窗口标记位、雨滴标记位
        printf("Yudi_vol:%.3f \r\n", voltage/10);
        printf("Window_flag = %d \r\n", Window_flag);
        printf("Rain_flag = %d \r\n", Rain_flag);

        if (NULL != app_msg)
        {
            app_msg->msg_type = en_msg_report;
            app_msg->msg.report.voltage = voltage;
            //app_msg->msg.report.Window_flag = Window_flag;
            //app_msg->msg.report.Rain_flag = Rain_flag;
            if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))
            {
                free(app_msg);
            }
        }
        
        usleep(3000000);//延时三秒
    }
    return 0;
}

static void IntelligenceBalcony(void)
{
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 10, NULL);
    if (mid_MsgQueue == NULL)
    {
        printf("Falied to create Message Queue!\n");
    }

    osThreadAttr_t attr;

    attr.name = "Intelligence_Balcony";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 24;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_main_entry!\n");
    }

    attr.stack_size = 2048;
    attr.priority = 25;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_sensor_entry!\n");
    }
}

APP_FEATURE_INIT(IntelligenceBalcony);
